package com.sz.biz.logistics.serialno.algorithm;

import com.sz.biz.logistics.serialno.constants.BillNumberConstants;

import javax.annotation.Nullable;
import javax.validation.constraints.NotNull;

/**
 * Package: com.sz.biz.logistics.channelno.algorithm<br>
 * Description: 校验码算法<br>
 * @author WuHan<br>
 * @date 2017-12-07 17:32<br>
 * @serial
 * @since sys-1.1.3
 */
public interface VerificationCodeAlgorithm {
    
    int ARRAY_LENGTH = 2;
    
    /**
     * 返回方法名
     */
    void getAlgorithmInfo();
    
    /**
     * 生成校验位
     * @param rawString 原始串号,如"ABB0123456?C"
     * @param pattern 待生成校验位的模式串,如"AB#*******?C"
     * @param formatRule 格式规则，当模式串形如 ABC123456?D-ABC234567?D 时，<br>无法判断某一位置具体是纯数字/纯字母还是混合类型，<br>为防止范围计算出错，加入基础原则进行辅助判断。
     * @return 带有校验位数字的串号
     */
    String generateVerificationCode(String rawString, @Nullable String pattern, String formatRule);
    
    /**
     * 单号的正确性验证
     * @param channelNumber 待验的单号,如"ABB01234565C"
     * @param pattern 待生成校验位的模式串,如"AB#*******?C"
     * @param formatRule 格式规则，当模式串形如 ABC123456?D-ABC234567?D 时，<br>无法判断某一位置具体是纯数字/纯字母还是混合类型，<br>为防止范围计算出错，加入基础原则进行辅助判断。
     * @return 是否符合校验规则
     */
    boolean validityCheck(String channelNumber, String pattern, String formatRule);

    /**
     * 验证是否满足校验位生成规则  支持 *****  也支持 111?---222?
     * @param serialNumber
     * @return
     */
    boolean checkSerialNumber(String serialNumber);
    
    default boolean checkValidityLength(String serialNumber, int validityLength) {
        
        //如果serialNumber中包含-
        if (serialNumber.contains(BillNumberConstants.Symbols.SYMBOL_SEPERATOR)) {
            String[] splitPatterns = serialNumber.split(BillNumberConstants.Symbols.SYMBOL_SEPERATOR);
            if (splitPatterns.length == ARRAY_LENGTH
                && splitPatterns[0].contains(BillNumberConstants.Symbols.SYMBOL_VERIFYCODE) && splitPatterns[1].contains(BillNumberConstants.Symbols.SYMBOL_VERIFYCODE)) {
                return splitPatterns[0].length() == splitPatterns[1].length() && splitPatterns[0].substring(0, splitPatterns[0].indexOf(BillNumberConstants.Symbols.SYMBOL_VERIFYCODE)).length()
                    == splitPatterns[1].substring(0, splitPatterns[1].indexOf(BillNumberConstants.Symbols.SYMBOL_VERIFYCODE)).length() && splitPatterns[0].substring(0, splitPatterns[0].indexOf(BillNumberConstants.Symbols.SYMBOL_VERIFYCODE)).length() >= validityLength;
            }
        }
        else {
            return serialNumber.contains(BillNumberConstants.Symbols.SYMBOL_VERIFYCODE) && serialNumber.indexOf(BillNumberConstants.Symbols.SYMBOL_VERIFYCODE) >= validityLength;
        }
        return false;
    }
    
    /**
     * 提取的恢复格式串中校验位的方法，针对格式串形如 "ABC#******" <br>而实际使用中模式串为 "ABCD41300?-ABDE50000?" 或 "ABCQ213**?"的情况。
     * @param pattern 模式串。
     * @param formatRule 格式规则，当模式串形如 ABC123456?D-ABC234567?D 时，<br>无法判断某一位置具体是纯数字/纯字母还是混合类型，<br>为防止范围计算出错，加入基础原则进行辅助判断。
     * @param containSeperator 模式串是否包含分隔符。
     * @return 更新的格式串，用作生成校验位。
     */
    default String restoreVerifyPosForFormatRule(@NotNull String pattern, String formatRule, boolean containSeperator) {
        if (containSeperator) {
            if (pattern.contains(BillNumberConstants.Symbols.SYMBOL_VERIFYCODE)
                    && !formatRule.contains(BillNumberConstants.Symbols.SYMBOL_VERIFYCODE)) {
                StringBuilder stringBuilder = new StringBuilder(formatRule);
                int pos = pattern.indexOf(BillNumberConstants.Symbols.SYMBOL_VERIFYCODE);
                stringBuilder.replace(pos, pos + 1, BillNumberConstants.Symbols.SYMBOL_VERIFYCODE);
                formatRule = stringBuilder.toString();
                pattern = formatRule;
            }
        }
        return pattern;
    }
}
